package manager;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import entity.Histogram;
import entity.Image;

public class FileManagerImpl implements IFileManager {

	private Histogram histogram;

	/* (non-Javadoc)
	 * @see manager.IFileManager#generateImage(java.lang.String)
	 */
	@Override
	public Image generateImage(String filepath) {

		Image image = null;
		try{
			BufferedReader reader = new BufferedReader(new FileReader(filepath));
			try {
				reader.readLine();

				String dimension = reader.readLine().trim();
				String[] dimensions = dimension.split(" ");
				int width = Integer.parseInt(dimensions[0]);
				int height = Integer.parseInt(dimensions[1]);
				int maxValue = Integer.parseInt(reader.readLine().trim().split(" ")[0]);

				int[][] imageMatrix = parseLines(readLines(reader)); 

				image = new Image(height, width, maxValue, imageMatrix, getHistogram(), filepath);

			} catch (Throwable e) {
				throw new RuntimeException("Ocorreu um erro ao tentar ler o arquivo.");
			}finally{
				reader.close();
			}
		}catch (Exception e) {
			throw new RuntimeException("Ocorreu um erro ao tentar ler o arquivo.");
		}
		return image;
	}

	/* (non-Javadoc)
	 * @see manager.IFileManager#generatePGM(entity.Histogram, entity.Image)
	 */
	@Override
	public Image generatePGM(Histogram histogram, Image image) {

		int[][] originalImage = image.getImage();
		int[][] newImage = new int[image.getWidth()][image.getHeight()];

		FileWriter writer = null;
		Date date = new Date();
		String time = Long.toString(date.getTime());
		try {
			writer = new FileWriter(new File(image.getFilepath().replaceAll(".pgm", "")+"_"+time+".pgm"));
			BufferedWriter bufferedWriter = new BufferedWriter(writer);
			bufferedWriter.write("P2");
			bufferedWriter.newLine();
			bufferedWriter.write(" "+image.getHeight()+" ");
			bufferedWriter.write(image.getWidth()+" ");
			bufferedWriter.newLine();
			bufferedWriter.write(" "+image.getMaxValue());
			bufferedWriter.newLine();
			Map<Integer, Integer> histogramMap = new TreeMap<Integer, Integer>();
			for (int row = 0; row < newImage.length; row++) {
				for (int col = 0; col < newImage[row].length; col++) {
					newImage[row][col] = histogram.getHistogram().get(originalImage[row][col]);
					if(histogramMap.containsKey(newImage[row][col])){
						int value = histogramMap.get(newImage[row][col]); 
						histogramMap.remove(newImage[row][col]);
						histogramMap.put(newImage[row][col], value+1);
					}else{
						histogramMap.put(newImage[row][col], 1);
					}
					bufferedWriter.write(String.valueOf(newImage[row][col])+" ");
				}
				bufferedWriter.newLine();
			}
			Histogram newHistogram = new Histogram(histogramMap);
			Image newImageObj = new Image(image.getHeight(), image.getWidth(), image.getMaxValue(), newImage, 
					newHistogram, image.getFilepath().replaceAll(".pgm", "")+"_"+time+".pgm");
			return newImageObj;
			
		} catch (Throwable t) {
			throw new RuntimeException("Erro ao tentar criar o arquivo "+image.getFilepath().replaceAll(".pgm", "")+"_"+time+".pgm", t);
		} finally{
			if (writer != null) {
				try {
					writer.close();
				} catch (Throwable t) {
					throw new RuntimeException("Erro ao tentar criar o arquivo "+image.getFilepath().replaceAll(".pgm", "")+"_"+time+".pgm", t);
				}
			}
		}
	}

	private int[][] parseLines(List<String> lines){

		final int rows = lines.size();
		final int cols = lines.get(0).split(" ").length;

		if (rows == 0){
			throw new IllegalArgumentException("Invalid number of rows!");
		}
		Map<Integer, Integer> histogramMap = new TreeMap<Integer, Integer>(); 
		int[][] matrix = new int[rows][cols];
		for (int row = 0; row < rows; row++){
			for (int col = 0; col < cols; col++){
				if(histogramMap.containsKey(Integer.parseInt((lines.get(row).split(" "))[col]))){
					int value = histogramMap.get(Integer.parseInt((lines.get(row).split(" "))[col])); 
					histogramMap.remove(Integer.parseInt((lines.get(row).split(" "))[col]));
					histogramMap.put(Integer.parseInt((lines.get(row).split(" "))[col]), value+1);
				}else{
					histogramMap.put(Integer.parseInt((lines.get(row).split(" "))[col]), 1);
				}
				matrix[row][col] = Integer.parseInt((lines.get(row).split(" "))[col]);
			}
		}

		this.histogram = new Histogram(histogramMap);

		return matrix;
	}

	private List<String> readLines(BufferedReader reader) throws IOException{
		List<String> lines = new ArrayList<String>();
		String line = reader.readLine();
		while (line != null)
		{
			lines.add(line);
			line = reader.readLine();
		}
		return lines;
	}

	public Histogram getHistogram() {
		return histogram;
	}

	public void setHistogram(Histogram histogram) {
		this.histogram = histogram;
	}

}
